﻿// owner 蒋家伟

#include "CommonFieldDescriptor.h"

// jsdk
#include "UniqueId.h"
#include "Dbg_Warn_Define.h"
#include "JsonUtils.h"
#include "HashUtils.h"

using namespace jsdk;

const char* CommonFieldDescriptor::s_pValue_Key = "Value";
const char* CommonFieldDescriptor::s_pClassUid_Key = "ClassType";

#pragma region CommonFieldDescriptrImp
namespace jsdk
{
    static constexpr char* s_pClassTypeHashCode_Key = "TypeHashCode";
    class CommonFieldDescriptrImp
    {
    public:
        CommonFieldDescriptrImp(
            const std::wstring& variableName,
            uint64_t v_offset,
            size_t typeHashCode,
            const std::wstring& v_typeName);
        const std::wstring& getVariableName() const;
        const uint64_t& getOffset() const;
        const std::wstring& getTypeName() const;
        const std::size_t& getTypeHashCode() const;
        const std::size_t& getSerializetypeHashCode() const;
        const std::wstring& getOwnerClassName() const;
        const jsdk::UniqueId& getOwnerClassUid() const;

        const void* getFiledAddress() const;
        void* getFiledAddress();
        void setClassAddress(void* pClassAddress);
        void setOwnerClassNameAndUid(const std::wstring& className, const jsdk::UniqueId& uid);
    private:
        std::wstring m_variableName = L"";
        uint64_t m_offset = 0;
        std::wstring m_typeName = L"";
        std::size_t m_typeHashCode = 0;
        std::size_t m_serializetypeHashCode = 0; // 序列化的hash值
        void* m_pClassAddress = nullptr;

        // 用于错误提示用
        std::wstring m_ownerClassName = L"";
        jsdk::UniqueId m_ownerClassUid = jsdk::UniqueId::s_InvalidUId;
    };

    std::wstring traitsTypeName(const std::wstring& sourceName) 
    {
        std::wstring res = sourceName;
        for (int i = static_cast<int>(res.size()) - 1; i >= 0;)
        {
            if (res[i] == L' ')
            {
                // 空格删掉
                res.erase(i, 1);
                i = i - 1;
                continue;
            }
            else if (res[i] == L':')
            {
                // 删除从当前开始，到 '< ' ，','
                int j = i-1;
                for (j; j >= 0; j--)
                {
                    if (res[j] == L'<' || res[j] == L',')
                    {
                        break;
                    }
                }
                res.erase(j+1, i - j);
                i = j - 1;
            }
            else
            {
                i = i - 1;
            }
        }

        return res;
    }
}

jsdk::CommonFieldDescriptrImp::CommonFieldDescriptrImp(
    const std::wstring& variableName, 
    uint64_t v_offset, 
    size_t typeHashCode,
    const std::wstring& v_typeName):
    m_variableName(variableName),
    m_offset(v_offset),
    m_typeName(v_typeName),
    m_typeHashCode(typeHashCode)
{
    // 删除类型名中的命名空间和空格
    std::wstring traitsName = traitsTypeName(v_typeName);
    size_t size = traitsName.size() * sizeof(wchar_t);
    m_serializetypeHashCode = HashUtils::bit_hash((const unsigned char*)(traitsName.c_str()), size);
}

const std::wstring& jsdk::CommonFieldDescriptrImp::getVariableName() const
{
    return m_variableName;
}

const uint64_t& jsdk::CommonFieldDescriptrImp::getOffset() const
{
    return m_offset;
}

const std::wstring& jsdk::CommonFieldDescriptrImp::getTypeName() const
{
    return m_typeName;
}

const std::size_t& jsdk::CommonFieldDescriptrImp::getTypeHashCode() const
{
    return m_typeHashCode;
}

const std::size_t& jsdk::CommonFieldDescriptrImp::getSerializetypeHashCode() const
{
    return m_serializetypeHashCode;
}

const std::wstring& jsdk::CommonFieldDescriptrImp::getOwnerClassName() const
{
    return m_ownerClassName;
}

const jsdk::UniqueId& jsdk::CommonFieldDescriptrImp::getOwnerClassUid() const
{
    return m_ownerClassUid;
}

const void* jsdk::CommonFieldDescriptrImp::getFiledAddress() const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pClassAddress, L"当前对象地址为空", L"蒋家伟", L"2023-11-30");
    return (const unsigned char*)(m_pClassAddress)+getOffset();
}


void* jsdk::CommonFieldDescriptrImp::getFiledAddress()
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pClassAddress, L"当前对象地址为空", L"蒋家伟", L"2023-11-30");
    return (unsigned char*)(m_pClassAddress)+getOffset();
}

void jsdk::CommonFieldDescriptrImp::setClassAddress(void* pClassAddress)
{
    m_pClassAddress = pClassAddress;
}

void jsdk::CommonFieldDescriptrImp::setOwnerClassNameAndUid(const std::wstring& className, const jsdk::UniqueId& uid)
{
    m_ownerClassName = className;
    m_ownerClassUid = uid;
}

#pragma region CommonFieldDescriptrImp

#pragma region CommonFieldDescriptor
jsdk::CommonFieldDescriptor::CommonFieldDescriptor(
    const std::wstring& variableName, 
    uint64_t v_offset, 
    size_t v_typeHashCode,
    const std::wstring& v_typeName):
    m_pCommonFieldDescriptrImp( NEW_AS_OWNERPTR(CommonFieldDescriptrImp, variableName, v_offset, v_typeHashCode, v_typeName).release() )
{
}

jsdk::CommonFieldDescriptor::~CommonFieldDescriptor()
{
    if (m_pCommonFieldDescriptrImp)
    {
        delete m_pCommonFieldDescriptrImp;
    }
}

const std::wstring& jsdk::CommonFieldDescriptor::getVariableName() const noexcept
{
    return m_pCommonFieldDescriptrImp->getVariableName();
}

const std::wstring& jsdk::CommonFieldDescriptor::getTypeName() const noexcept
{
    return m_pCommonFieldDescriptrImp->getTypeName();
}

const std::size_t& jsdk::CommonFieldDescriptor::getTypeHashCode() const noexcept
{
    return m_pCommonFieldDescriptrImp->getTypeHashCode();
}

const void* jsdk::CommonFieldDescriptor::getFiledAddress() const noexcept
{
    return m_pCommonFieldDescriptrImp->getFiledAddress();
}

void* jsdk::CommonFieldDescriptor::getFiledAddress() noexcept
{
    return m_pCommonFieldDescriptrImp->getFiledAddress();
}

void jsdk::CommonFieldDescriptor::setClassAddress(void* pClassAddress) noexcept
{
    m_pCommonFieldDescriptrImp->setClassAddress(pClassAddress);
}

void jsdk::CommonFieldDescriptor::setOwnerClassNameAndUid(const std::wstring& className, const jsdk::UniqueId& uid) noexcept
{
    m_pCommonFieldDescriptrImp->setOwnerClassNameAndUid(className, uid);
}

jsdk::OwnerPtr<jsdk::DBSchemaObject> jsdk::CommonFieldDescriptor::getCastDBSchemaObject(jsdk::OwnerPtr<DBSchemaObject> opSourceDBSchemaObject) const noexcept
{
    return nullptr;
}

bool jsdk::CommonFieldDescriptor::serialize(JsonDocument& jsonDoc, JsonObject& jsonObject) const noexcept
{
    // 将类别hash值序列化到文档中，用于反序列化对当前定义类型做检查。保证类型不变才能正确序列化数据
    JsonUtils::insert(jsonDoc, jsonObject, s_pClassTypeHashCode_Key, JsonUtils::getDataStream(this->getSerializetypeHashCode(), jsonDoc));
    return serializeValue(jsonDoc, jsonObject);
}

bool jsdk::CommonFieldDescriptor::unserialize(const JsonObject& jsonObject) noexcept
{
    // todo 后续对象做类别升级时，从当前地方以回调形式开放出去
    // 所有对象反序列化开始，都要对文档中的uid与程序此时的uid做对比。保证数据类型一直才能发序列化
    std::size_t typeHashCode = 0;
    bool success = JsonUtils::getValueFromJsonValue(JsonUtils::getJsonValue(jsonObject, s_pClassTypeHashCode_Key), typeHashCode) ;
    DBG_WARN_AND_RETURN_FALSE_UNLESS(success, this->getErrorMsgPrefix() + L"获取类别Hash值失败", L"蒋家伟", L"2023-11-30");
    DBG_WARN_AND_RETURN_FALSE_UNLESS(this->getSerializetypeHashCode() == typeHashCode, this->getErrorMsgPrefix() + L"类别变化, 是否发生变动？", L"蒋家伟", L"2023-11-30");
    return unserializeValue(jsonObject);
}

const uint64_t& jsdk::CommonFieldDescriptor::getOffset() const
{
    return m_pCommonFieldDescriptrImp->getOffset();
}

const std::size_t& jsdk::CommonFieldDescriptor::getSerializetypeHashCode() const
{
    return m_pCommonFieldDescriptrImp->getSerializetypeHashCode();
}

bool jsdk::CommonFieldDescriptor::schemaObjectSerialize(JsonDocument& jsonDoc, JsonObject& jsonObject, const jsdk::UniqueId& typeUid, JsonObject&& jsonObjectValue)
{
    // 将自定义继承体系的uid与值写入，反序列化时用来反射与反流
    JsonUtils::insert(jsonDoc, jsonObject, CommonFieldDescriptor::s_pClassUid_Key, JsonUtils::getDataStream(typeUid, jsonDoc));
    JsonUtils::insert(jsonDoc, jsonObject, CommonFieldDescriptor::s_pValue_Key, std::move(jsonObjectValue));
    return true;
}

bool jsdk::CommonFieldDescriptor::getClassUidFromJsonObject(const JsonObject& jsonObject, jsdk::UniqueId& uid)
{
    if (const JsonValue* pClassName = JsonUtils::getJsonValue(jsonObject, s_pClassUid_Key))
    {
        return JsonUtils::getValueFromJsonValue(pClassName, uid);
    }
    return false;
}

std::wstring jsdk::CommonFieldDescriptor::getErrorMsgPrefix() const
{
    return   L"所属类别名称: " + m_pCommonFieldDescriptrImp->getOwnerClassName() + 
             L"\n所属类别UID: " + m_pCommonFieldDescriptrImp->getOwnerClassUid().toString() +
             L"\n类别名称: " + getTypeName() + 
             L"\n变量名称: " + getVariableName();
}

#pragma region CommonFieldDescriptor
